import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class WorkCounter {

    public static final Path FOLDER_OF_TEXT_FILES = Paths.get("file/input");
    public static final Path WORD_COUNT_TABLE_FILE = Paths.get("file/result.txt");
    public static final int NUMBER_OF_THREADS = 2;

    public static void main(String[] args) {
        try {
            Map<String, Map<String, Integer>> fileWordMap = readFolderFile();
            writeStat(fileWordMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);

    }

    private static void writeStat(Map<String, Map<String, Integer>> fileWordMap) {
        List<String> fileNameList = new ArrayList<>(fileWordMap.keySet());
        Set<String> allWords = new HashSet<>();
        int lengthestFileName = 0;
        for (String fileName : fileWordMap.keySet()) {
            allWords.addAll(fileWordMap.get(fileName).keySet());
            if (fileName.length() > lengthestFileName) {
                lengthestFileName = fileName.length();
            }
        }
        List<String> allWordList = new ArrayList<>(allWords);
        Collections.sort(allWordList);
        Collections.sort(fileNameList);

        Object[] headers = new Object[fileNameList.size() + 2];
        String tpl = "%-" + (lengthestFileName + 1) + "s";
        headers[0]="";
        for (int i = 0; i < fileNameList.size(); i++) {
            String fileName = fileNameList.get(i);
            tpl += "%-" + (fileName.length() + 4) + "s";
            headers[i + 1] = fileName;
        }
        tpl += "%s";
        headers[fileNameList.size() + 1] = "total";

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(String.format(tpl, headers)).append(System.lineSeparator());

        for (int j = 0; j < allWordList.size(); j++) {
            String word = allWordList.get(j);
            Object[] wordCounts = new Object[fileNameList.size() + 2];
            wordCounts[0] = word;
            int totalCount = 0;
            for (int i = 0; i < fileNameList.size(); i++) {
                String filename = fileNameList.get(i);
                int count = fileWordMap.get(filename).getOrDefault(word, 0);
                totalCount += count;
                wordCounts[i + 1] = count;
            }
            wordCounts[fileNameList.size() + 1] = totalCount;
            stringBuilder.append(String.format(tpl, wordCounts));
            if (j < allWordList.size() - 1) {
                stringBuilder.append(System.lineSeparator());
            }
        }

        String message = stringBuilder.toString();
        System.out.println(message);

        try (PrintWriter printWriter = new PrintWriter(new FileWriter(WORD_COUNT_TABLE_FILE.toFile()))) {
            printWriter.write(message);
            printWriter.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static Map<String, Map<String, Integer>> readFolderFile() throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(NUMBER_OF_THREADS);
        File file = FOLDER_OF_TEXT_FILES.toFile();
        if (!file.exists() || !file.isDirectory()) {
            return new HashMap<>();
        }
        Map<String, Map<String, Integer>> filesMap = new ConcurrentHashMap<>();
        CountDownLatch countDownLatch = new CountDownLatch(file.listFiles().length);
        for (File fileTmp : file.listFiles()) {
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    if (fileTmp.isFile()) {
                        Map<String, Integer> map = readFileWords(fileTmp);
                        filesMap.put(fileTmp.getName(), map);
                    }
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        return filesMap;
    }

    private static Map<String, Integer> readFileWords(File fileTmp) {
        Map<String, Integer> map = new HashMap<>();
        try (BufferedReader bufferedReader = new BufferedReader(new FileReader(fileTmp))) {
            while (bufferedReader.ready()) {
                String line = bufferedReader.readLine();
                for (String word : line.split(" ")) {
                    word = word.toLowerCase();
                    while (true) {
                        char lastChar = word.charAt(word.length() - 1);
                        if (lastChar >= 'a' && lastChar <= 'z') {
                            break;
                        } else {
                            word = word.substring(0, word.length() - 1);
                        }
                    }

                    if (word.length() > 0) {
                        int count = map.getOrDefault(word, 0);
                        map.put(word, count + 1);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

}
